#pragma once
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <optional>

#include "common/rw_mutex.h"
#include "option/config.h"

namespace boltDB {
enum class PageType : uint16_t {
  EmptyPage = 0x00,
  BranchPage = 0x01,
  LeafPage = 0x02,
  MetaPage = 0x04,
  FreelistPage = 0x10
};

/*
  pageheader结构
  uint32_t page_id_; 页id
  uint32_t overflow_; 是否溢出，如果没有溢出overflow = 0xFFFFFFFF,
                      否则是溢出的数据所在的页号
  uint16_t page_type_;页类型
  uint16_t count_;    包含元素的个数
*/

class Page {
  friend class BufferPoolManager;

 public:
  class PageHeader {
   public:
    static constexpr size_t PAGE_ID_OFFSET = 0;
    static constexpr size_t OVERFLOW_OFFSET = 4;
    static constexpr size_t PAGE_TYPE_OFFSET = 8;
    static constexpr size_t COUNT_OFFSET = 10;
    PageHeader(char* data) {
      header_ = data;
      size_ = SIZE_PAGE_HEADER;
    }
    auto GetPageId() -> page_id_t {
      char* ptr = header_ + PAGE_ID_OFFSET;
      uint32_t* page_id = reinterpret_cast<uint32_t*>(ptr);
      return *page_id;
    };

    auto IsOverflow() -> std::optional<uint32_t> {
      char* ptr = header_ + OVERFLOW_OFFSET;
      uint32_t* overflow_page = reinterpret_cast<uint32_t*>(ptr);
      if (*overflow_page == uint32_t(-1)) {
        return std::nullopt;
      } else {
        return *overflow_page;
      }
    };

    auto Type() -> const PageType* {
      char* ptr = header_ + PAGE_TYPE_OFFSET;
      return reinterpret_cast<PageType*>(ptr);
    };

    auto Count() -> uint16_t {
      char* ptr = header_ + COUNT_OFFSET;
      uint16_t* count = reinterpret_cast<uint16_t*>(ptr);
      return *count;
    };
    auto size() -> size_t const { return size_; }

   private:
    char* header_;
    size_t size_;
  };
  Page() {
    data_ = new char[BOLTDB_PAGE_SIZE];
    ResetMemory();
  }

  ~Page() { delete[] data_; }

  inline auto GetData() -> char* { return data_; }

  inline auto GetPageId() -> page_id_t { return page_id_; }

  inline auto GetRefCount() -> int { return ref_count_; }

  inline auto IsDirty() -> bool { return is_dirty_; }

  inline void WLatch() { rwlatch_.WLock(); }

  inline void WUnlatch() { rwlatch_.WUnlock(); }

  inline void RLatch() { rwlatch_.RLock(); }

  inline void RUnlatch() { rwlatch_.RUnlock(); }

  PageHeader GetHeader() { return PageHeader(data_); }

 protected:
  static_assert(sizeof(page_id_t) == 4);

  static constexpr size_t SIZE_PAGE_HEADER = 12;
  static constexpr size_t OFFSET_PAGE_OFFSET = 0;

 private:
  inline void ResetMemory() {
    memset(data_, OFFSET_PAGE_OFFSET, BOLTDB_PAGE_SIZE);
  }
  // 这个用指针是为了方便slice的转换，如果没有slice，实际上其实用char[]好一点
  char* data_;
  /* 页ID*/
  page_id_t page_id_ = INVALID_PAGE_ID;
  /*引用次数*/
  int ref_count_ = 0;
  /*脏页*/
  bool is_dirty_ = false;
  /* 读写锁 */
  RWMutex rwlatch_;
};

}  // namespace boltDB